package ro.prjmanager.service;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import ro.prjmanager.core.service.AbstractService;
import ro.prjmanager.dao.*;
import ro.prjmanager.database.model.Table;
import ro.prjmanager.helpers.ModelsTablesHelper;
import ro.prjmanager.model.Columns;
import ro.prjmanager.model.Models;
import ro.prjmanager.model.TableSet;
import ro.prjmanager.service.resolvers.SynchResolver;

import java.util.List;

public class SyncService extends AbstractService implements SynchInterfaceService {

    private ModelsDao modelsDao;
    private TableSetDao tableSetDao;
    private ColumnsDao columnsDao;
    private ForeignModelDao foreignModelDao;


    public SynchDao getDao() {
        return (SynchDao) dao;
    }

    public ModelsDao getModelsDao() {
        return modelsDao;
    }

    public void setModelsDao(ModelsDao modelsDao) {
        this.modelsDao = modelsDao;
    }

    public ColumnsDao getColumnsDao() {
        return columnsDao;
    }

    public void setColumnsDao(ColumnsDao columnsDao) {
        this.columnsDao = columnsDao;
    }

   

    public TableSetDao getTableSetDao() {
        return tableSetDao;
    }

    public void setTableSetDao(TableSetDao tableSetDao) {
        this.tableSetDao = tableSetDao;
    }

    public ForeignModelDao getForeignModelDao() {
        return foreignModelDao;
    }

    public void setForeignModelDao(ForeignModelDao foreignModelDao) {
        this.foreignModelDao = foreignModelDao;
    }

    public void clean() {
        int countCols = getColumnsDao().no("");
        if (countCols > 0) {
            getModelsDao().executeDML("delete from prjmanager.columns where relation_columns is not null");
            getModelsDao().executeDML("delete from prjmanager.columns where foreign_column is not null");
            getModelsDao().executeDML("delete from prjmanager.columns");
            getModelsDao().executeDML("delete from prjmanager.FOREIGN_MODEL");

        }
    }

    public List<String> load(String url, String user, String pwd, String schema, int type) {

        return getDao().getAllTableFromSchema(url, user, pwd, schema, type);
    }

    public static final Log log = LogFactory.getLog(SyncService.class);

    private Models mergedModel(Models dbModels, Models synchModels) {
        if (synchModels == null)
            return dbModels;

        dbModels.setClassExtend(synchModels.getClassExtend());
        dbModels.setDatabaseName(synchModels.getDatabaseName());
        dbModels.setDatabasePk(synchModels.getDatabasePk());
        dbModels.setIsExtend(synchModels.getIsExtend());
        dbModels.setJavaName(synchModels.getJavaName());
        dbModels.setPkClass(synchModels.getPkClass());
        dbModels.setUnidirectionalAssociation(synchModels.getUnidirectionalAssociation());
        dbModels.setColumns(synchModels.getColumns());

        for (Columns cols : dbModels.getColumns()) {
            cols.setOwnerTable(dbModels);
        }


        return dbModels;

    }


    private void doSynch(String url, String user, String pwd, String schema, int type, String tableName) {
       Table table = getDao().syncTable(url, user, pwd, schema, type, tableName);
        Models model = ModelsTablesHelper.cast(table);
        List<Models> modelDbs = getModelsDao().find(model);
        if (modelDbs == null || modelDbs.isEmpty()) {
           TableSet tableSetT = new TableSet();
            tableSetT.setTableName(tableName);
            TableSet tableSet = tableSetDao.find(tableSetT).get(0);
            if (tableSet != null) {
                Models modelNew = new Models();
                modelNew.setTableName(tableName);
                modelNew.setFkProjectDb(tableSet.getFkProjectDb());
                Models merged = mergedModel(modelNew, model);
                getModelsDao().create(merged);
                getTableSetDao().delete(tableSet.getId());
            } else
                throw new RuntimeException("Tabela cu numele " + model.getDatabaseName() + " nu este in setul activ de tabele pentru proiectul curent!!");
        } else {

            Models merged = mergedModel(modelDbs.get(0), model);


            getModelsDao().update(merged);
        }
    }

    public static final boolean DO_NOT_DELETE_ASSOCIATED_TABLE_SET = false;

    public void syncTable(String url, String user, String pwd, String schema, int type, List<TableSet> tableSetList) {
        if (tableSetList != null && tableSetList.size() > 0) {
            SynchResolver resolver = new SynchResolver(tableSetList, DO_NOT_DELETE_ASSOCIATED_TABLE_SET);
            resolver.setColumnsDao(columnsDao);
            resolver.setForeignModelDao(foreignModelDao);
            resolver.setModelsDao(modelsDao);
            resolver.setTableSetDao(tableSetDao);
            resolver.cleanAffectedEntitiesList();


            List<Models> models = resolver.getAffectedModels();
            if (models != null && models.size() > 0) {
                for (Models mod : models) {
                    doSynch(url, user, pwd, schema, type, mod.getTableName());
                }

            } else {
                for (TableSet tableSet : tableSetList)
                    doSynch(url, user, pwd, schema, type, tableSet.getTableName());
            }
        }
    }

    public void syncTable(String url, String user, String pwd, String schema, int type, TableSet tableSet) {
        tableSet = tableSetDao.find(tableSet.getId(), false);
        SynchResolver resolver = new SynchResolver(tableSet, DO_NOT_DELETE_ASSOCIATED_TABLE_SET);
        resolver.setColumnsDao(columnsDao);
        resolver.setForeignModelDao(foreignModelDao);
        resolver.setModelsDao(modelsDao);
        resolver.setTableSetDao(tableSetDao);
        resolver.cleanAffectedEntities();
        List<Models> models = resolver.getAffectedModels();
        if (models != null && models.size() > 0) {
            for (Models mod : models) {
                doSynch(url, user, pwd, schema, type, mod.getTableName());
            }

        } else {
            doSynch(url, user, pwd, schema, type, tableSet.getTableName());
        }
    }

    public static final boolean DELETE_ASSOCIATED_TABLE_SET = true;

    public void removeTableSet(String url, String user, String pwd, String schema, int type, TableSet tableSet) {
        tableSet = tableSetDao.find(tableSet.getId(), false);
        SynchResolver resolver = new SynchResolver(tableSet, DELETE_ASSOCIATED_TABLE_SET);
        resolver.setColumnsDao(columnsDao);
        resolver.setForeignModelDao(foreignModelDao);
        resolver.setModelsDao(modelsDao);
        resolver.setTableSetDao(tableSetDao);
        resolver.cleanAffectedEntities();
        List<Models> models = resolver.getAffectedModels();
        for (Models mod : models) {
            if (!mod.getId().equals(tableSet.getId()))
                doSynch(url, user, pwd, schema, type, mod.getTableName());
        }
    }

    public static void main(String[] args) {
        System.out.println(TableSet.class.getName());
    }

    public void create(Object entity) {

    }

    public void delete(Object o) {

    }

    public Object load(Object o) {
        return null;
    }

    public List listPag(int startPage, int resPerPage) {
        return null;
    }

    public List listPag(int startPage, int resPerPage, String orderCol, boolean asc, Object[] otherItems) {
        return dao.listPag(startPage, resPerPage, orderCol, asc, otherItems);
    }

    public List list() {
        return dao.findAll();
    }

    public List listPagFilter(int startPage, int resPerPage, String filter) {
        return null;
    }

    public int no(String filter) {
        return dao.no(filter);
    }

    public void update(Object entity) {

    }
}
